package com.cd2cd.code_template.configuration.security;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.annotation.Resource;

import com.alibaba.fastjson.JSONObject;
import com.cd2cd.code_template.code_template.domain.SysAuth;
import com.cd2cd.code_template.code_template.mapper.SysAuthMapper;
import com.cd2cd.code_template.configuration.constants.DBConstants;
import com.cd2cd.code_template.configuration.handler.EntryPointUnauthorizedHandler;
import com.cd2cd.code_template.configuration.handler.RestAccessDeniedHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.core.GrantedAuthorityDefaults;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;

import org.springframework.security.web.context.SecurityContextPersistenceFilter;


/**
 * RBAC控制 <br>
 * 权限加载 用户的角色改变或角色的权限改变都需在更新所有登录用户的权限
 */
@Slf4j
@Configuration
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {

    /**
     * 不拦截开头url地址; TokenOncePerRequestFilter startWith 判断
     */
    public static final String[] START_WITH_PERMIT_ALL_URL = new String[]{
            "/admin",
            "/comm",
            "/captcha"
    };

    @Resource
    private TokenOncePerRequestFilter tokenOncePerRequestFilter;

    @Resource
    private EntryPointUnauthorizedHandler entryPointUnauthorizedHandler;

    @Resource
    private RestAccessDeniedHandler restAccessDeniedHandler;

    private SessionRegistry sessionRegistry;

    @Bean
    protected SessionRegistry getSessionRegistry() {
        sessionRegistry = new SessionRegistryImpl();
        return sessionRegistry;
    }

    @Resource
    private SysAuthMapper sysAuthMapper;

    @Bean
    GrantedAuthorityDefaults grantedAuthorityDefaults() {
        return new GrantedAuthorityDefaults(""); // Remove the ROLE_ prefix
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        /**
         * 禁用: cors csrf httpBasic frameOptions(frame,iframe,embed,object) disable
         */
        http.cors().disable().csrf().disable().httpBasic().disable().headers().frameOptions().disable();

        http.headers().cacheControl();

        initAuthorities(http); // 初始化权限

        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); // 无session状态


        String[] permitAll = Stream.of(START_WITH_PERMIT_ALL_URL).map(m-> m+"/**").collect(Collectors.toList()).toArray(new String[]{});

        log.info("permitAll={}", JSONObject.toJSONString(permitAll));

        http
                .authorizeRequests()
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
                .antMatchers(permitAll).anonymous()
                .anyRequest().authenticated()
        ;

        http.addFilterAfter(tokenOncePerRequestFilter, SecurityContextPersistenceFilter.class);

        // handling
        http.exceptionHandling()
                .authenticationEntryPoint(entryPointUnauthorizedHandler)// 身份认证
                .accessDeniedHandler(restAccessDeniedHandler) // 授权
        ;

    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        super.configure(auth);
    }

    /**
     * 初始化系统权限内容
     *
     * @param http
     */
    private void initAuthorities(HttpSecurity http) {

        List<SysAuth> list = sysAuthMapper.queryListByAuthVal(DBConstants.BoolStr.YES);
        try {
            for (SysAuth auth : list) {
                String role = auth.getGuid();
                String name = auth.getName();
                String url = auth.getUrl();
                if(StringUtils.isNotBlank(url)) {
                    http.authorizeRequests().antMatchers(url).hasRole(role);
                }
                log.info("init all Authorities, name={}, role={}, url={}", name, role, url);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public static void main(String[] args) {

        String[] permitAll = Stream.of(START_WITH_PERMIT_ALL_URL).map(m->m+"/**").collect(Collectors.toList()).toArray(new String[]{});
        System.out.println(permitAll[1]+"-"+permitAll[0]);

    }
}